/* caesar.c
**
** Copyright (c) 2007, Meadhbh S. Hamrick
** All rights reserved.
** 
** Redistribution  and  use  in  source  and  binary  forms,  with  or  without
** modification, are permitted provided that the following conditions are met:
** 
**  * Redistributions of  source code must  retain the above  copyright notice,
**    this list of conditions and the following disclaimer.
** 
**  * Redistributions in binary form must reproduce the above copyright notice,
**    this list of conditions and the following disclaimer in the documentation
**    and/or other materials provided with the distribution.
** 
**  * Neither the  name of  Project Meadhbh  nor the names of  its contributors
**    may be used  to endorse  or promote  products derived from this  software
**    without specific prior written permission.
** 
** THIS SOFTWARE IS PROVIDED BY  THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY  EXPRESS OR IMPLIED WARRANTIES,  INCLUDING, BUT NOT  LIMITED TO, THE
** IMPLIED WARRANTIES  OF MERCHANTABILITY AND FITNESS FOR  A PARTICULAR PURPOSE
** ARE DISCLAIMED.  IN NO  EVENT SHALL THE  COPYRIGHT OWNER OR  CONTRIBUTORS BE
** LIABLE  FOR  ANY  DIRECT,   INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
** CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT  OF
** SUBSTITUTE GOODS  OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
** INTERRUPTION)  HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN
** CONTRACT,  STRICT LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE OR  OTHERWISE)
** ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
** 
** $Id: caesar.c 66 2007-11-08 07:18:51Z msh.mobile $
*/

/** \file caesar.c
**  This  file  implements  the   CAESAR  cipher.  Though  it's  really  a
**  transposition cipher,  we're including it  in with the  stream ciphers
**  because it doesn't take a block mode.
**
** It's kinda  funny that  a "serious" crypto  library is  implementing a
** Caesar  cipher.  But  what's  funnier  is that  people  have  actually
** asserted that old school transposition ciphers are acceptable for real
** security. Several  years ago Adobe  made the mistake of  letting third
** parties  define  security  profiles  as  part of  an  Acrobat  related
** product.  As an  example, they  showed  how to  "protect" contents  of
** documents  using  ROT13.   Several  third  party  implementers  didn't
** understand that it  was an example only and  dutifully implemented the
** ROT13 "encryption"  algorithm. So, we're  adding the Caesar  cipher in
** case you have to work with Adobe products.
** 
** Since I'm  dealing with  a brain-dead "cipher,"  I might as  well have
** some  fun  with  it.  I'm  including three  modes:  classic,  95C  and
** 8-bit. Classic mode is the  "classic" Caesar cipher. You pick a number
** between  0 and  25 and  all characters  are replaced  with  the letter
** that's that many  places down in alphabetical order.  In this mode, we
** only  work   on  [A-Z]   and  [a-z].  Numbers,   punctuation,  control
** characters, etc. are unaffected.
** 
** In 95C mode,  you pick a number between 0 and  94. All printable ASCII
** characters are  substituted with characters that many  places down the
** ASCII chart. This  has the affect of masking  numbers and punctuation,
** but preserving control characters.
** 
** In 8-bit mode,  a "key" between 0 and 255 is  selected and this number
** is  added  (modulo  256)  to  each character.  It  does  not  preserve
** punctuation.
** 
** Keys   and  modes   are  passed   to   the  mc_ssc_caesar_initialize()
** function. Here's a few examples:
** 
** * mc_ssc_caesar_initialize( context, MC_SSC_CAESAR_MODE_CLASSIC, 13 ) - classic ROT13
** * mc_ssc_caesar_initialize( context, MC_SSC_CAESAR_MODE_95C, 17 )     - rotates printable characters by 17 places
** * mc_ssc_caesar_initialize( context, MC_SSC_CAESAR_MODE_8BIT, 91 )    - effectively adds 91 to each character
** 
** All this is  terribly western-oriented; there's a strong  focus on the
** Roman  alphabet  and  no  accomodation  is given  for  UTF-8  or  wide
** characters.  I guess  that's  because it's  the  "Caesar" cipher.  But
** seriously, if someone wanted to do something fun, but a total waste of
** time, they  could come up with a  scheme for doing a  Caesar cipher on
** UTF-8 input streams.
*/

/* Macro Definitions */
#define MC_SSC_CAESAR_MASK_KEY    0x000000FF
#define MC_SSC_CAESAR_MASK_MODE   0x00000300

#define MC_SSC_CAESAR_MODE(k,m) ( ( ( k ) & MC_SSC_CAESAR_MASK_KEY ) | ( m ) )

/* File Includes */
#include "mutil.h"
#include "mcrypto/caesar.h"

/* Static Prototypes */
static void mc_ssc_caesar_update( uint32_t key, uint32_t mode, uint8_t *input, uint32_t input_length, uint8_t *output, uint32_t output_length, uint32_t *bytes_written );
static uint32_t mc_ssc_caesar_modulus( uint32_t mode );

/* Static Variables */

/** \fn void mc_ssc_caesar_clone( tMCCaesar *new, tMCCaesar *old )
**  \brief copy the state of an CAESAR context
*/
void mc_ssc_caesar_clone( tMCCaesar *new_context, tMCCaesar *old_context ) {
  memcpy( new_context, old_context, sizeof( tMCCaesar ) );
}

/** \fn void mc_ssc_caesar_clear( tMCCaesar *context )
**  \brief clear sensitive data from the context
*/
void mc_ssc_caesar_clear( tMCCaesar *context ) {
  context->mode = 0;
}

/** \fn void mc_ssc_caesar_initialize( tMCCaesar *context, uint32_t mode, uint32_t key )
**  \brief initialize a CAESAR context with the mode and key
*/
void mc_ssc_caesar_initialize( tMCCaesar *context, uint32_t mode, uint32_t key ) {
  context->mode = MC_SSC_CAESAR_MODE( ( key % mc_ssc_caesar_modulus(mode) ) , mode );
}

void mc_ssc_caesar_encrypt( tMCCaesar *context, uint8_t *input, uint32_t input_length, uint8_t *output, uint32_t output_length, uint32_t *bytes_written ) {
  mc_ssc_caesar_update( (context->mode & MC_SSC_CAESAR_MASK_KEY), (context->mode & MC_SSC_CAESAR_MASK_MODE), input, input_length, output, output_length, bytes_written );
}

void mc_ssc_caesar_decrypt( tMCCaesar *context, uint8_t *input, uint32_t input_length, uint8_t *output, uint32_t output_length, uint32_t *bytes_written ) {
  mc_ssc_caesar_update( ( mc_ssc_caesar_modulus( context->mode & MC_SSC_CAESAR_MASK_MODE ) - ( context->mode & MC_SSC_CAESAR_MASK_KEY ) ), context->mode & MC_SSC_CAESAR_MASK_MODE, input, input_length, output, output_length, bytes_written );
}
 
/** \fn void mc_ssc_caesar_update( uint32_t key, uint32_t mode, uint8_t *input, uint32_t input_length, uint8_t *output, uint32_t output_length, uint32_t *bytes_written )
**  \brief encrypt plaintext using an initialized context
*/
static void mc_ssc_caesar_update( uint32_t key, uint32_t mode, uint8_t *input, uint32_t input_length, uint8_t *output, uint32_t output_length, uint32_t *bytes_written ) {
  uint32_t count, i;
  int32_t t;

  if( input_length > output_length ) {
    count = output_length;
  } else {
    count = input_length;
  }

  for( i = 0; i < count; i++ ) {
    switch( mode ) {
    case MC_SSC_CAESAR_MODE_CLASSIC:
      if( ( input[i] >= 'A' ) && ( input[i] <= 'Z' ) ) {
	output[ i ] = ( ( ( input[ i ] - 'A' ) + key ) % 26 ) + 'A' ;
      } else if( ( input[ i ] >= 'a' ) && ( input[ i ] <= 'z' ) ) {
	output[ i ] = ( ( ( input[ i ] - 'a' ) + key ) % 26 ) + 'a' ;
      }
      break;
    case MC_SSC_CAESAR_MODE_95C:
      if( ( input[i] >= 32 ) && ( input[i] <= 126 ) ) {
	output[i] =
          ( ( ( input[i] - 32 ) + key ) % 95 ) + 32;
      }
      break;
    case MC_SSC_CAESAR_MODE_8BIT:
      output[ i ] = (uint8_t) ( (uint32_t ) input[ i ] + key );
      break;
    }
  }

  if( NULL != bytes_written ) {
    *bytes_written = count;
  }
}

static uint32_t mc_ssc_caesar_modulus( uint32_t mode ) {
  uint32_t modulus;

  switch( mode ) {
  case MC_SSC_CAESAR_MODE_CLASSIC:
    modulus = 26;
    break;
  case MC_SSC_CAESAR_MODE_95C:
    modulus = 95;
    break;
  case MC_SSC_CAESAR_MODE_8BIT:
    modulus = 256;
    break;
  }

  return( modulus );
}
 
#if defined( MC_SSC_CAESAR_PRINT )
void mc_ssc_caesar_print( tMCCaesar *context ) {
  printf( "  {\n" );
  printf( "    .mode = 0x%08X,\n", context->mode );
  printf( "  },\n");
}
#endif
